// #pragma once

// #include<queue>
// #include<string>
// #include<cstdlib>
// #include<ctime>
// #include<pthread.h>
// #include<unistd.h>

// const uint32_t gDefaultCap = 5;

// template<class T>
// class BlockQueue
// {
// public:
//     BlockQueue(uint32_t cap = gDefaultCap)
//         :cap_(cap)
//     {
//         pthread_mutex_init(&mutex_, nullptr);
//         pthread_cond_init(&conCond_, nullptr);
//         pthread_cond_init(&proCond_, nullptr);
//     }
//     ~BlockQueue()
//     {
//         pthread_mutex_destroy(&mutex_);
//         pthread_cond_init(&conCond_, nullptr);
//         pthread_cond_init(&proCond_, nullptr);
//     }

// public:
//     //生产接口
//     void push(const T& in)
//     {
//         //加锁
//         //判断-是否适合生产-bq_是否为满-程序员视角的条件-1.满(不生产) 2.不满(生产)
//         //if(满) 不生产, 休眠; else if(不满) 生产, 唤醒消费者
//         //解锁

//         lockQueue();

//         while(isFull())// isFull()是我们在临界区设定的条件
//         {
//             //before: 当我们等待的时候会自动释放mutex_
//             proBlockWait();//生产者阻塞等待, 等待被唤醒
//             //after: 当我醒来的时候, 我是在临界区里醒的
//         }

//         //条件满足, 可以生产
//         pushCore(in);//生产完成

//         unlockQueue();

//         wakeupCon(); // 唤醒消费者
//     }

//     //消费接口
//     T pop()
//     {
//         //加锁
//         //判断-是否适合消费-bq_是否为空-程序员视角的条件-1.空:不消费; 2.非空:消费
//         //if(空): 不消费, 休眠; else if(非空): 消费, 唤醒生产者
//         //解锁

//         lockQueue();

//         while(isEmpty())
//         {
//             conBlockWait();//消费者阻塞等待, 等待被唤醒
//         }
//         //条件满足, 可以消费
//         T tmp = popCore();

//         unlockQueue();

//         wakeupPro();//唤醒生产者

//         return tmp;
//     }

// private:
//     void lockQueue()
//     {
//         pthread_mutex_lock(&mutex_);
//     }

//     void unlockQueue()
//     {
//         pthread_mutex_unlock(&mutex_);
//     }

//     bool isEmpty()
//     {
//         return bq_.empty();
//     }

//     bool isFull()
//     {
//         return cap_ == bq_.size();
//     }

//     void proBlockWait()//生产者一定是在临界区中的
//     {
//         //在阻塞线程的时候, 会自动释放mutex_锁
//         pthread_cond_wait(&proCond_, &mutex_);
//     }

//     void conBlockWait()//阻塞等待, 等待被唤醒
//     {
//         //1.在阻塞线程的时候, 会自动释放mutex_锁
//         pthread_cond_wait(&conCond, &mutex_);
//         //2.当阻塞结束返回的时候, pthread_cond_wait()会自动帮你重新获得mutex_锁, 然后才返回
//     }

//     void wakeupPro()//唤醒生产者
//     {
//         pthread_cond_signal(&proCond_);
//     }

//     void wakeupCon()//唤醒消费者
//     {
//         pthread_cond_signal(&conCond_);
//     }

//     void pushCore(const T& in)
//     {
//         bq_.push(in);
//     }

//     T popCore()
//     {
//         T tmp = bq_.front();
//         bq_.pop();
//         return tmp;
//     }


// private:
//     uint32_t cap_; // 容量
//     std::queue<T> bq_; // blockqueue
//     pthread_mutex_t mutex_; // 保护阻塞队列
//     pthread_cond_t conCond_; // 让消费者等待的条件变量
//     pthread_cond_t proCond_; // 让生产者等待的条件变量
// };


// #pragma once

// #include<iostream>
// #include<cstdio>
// #include<queue>
// #include<pthread.h>

// using namespace std;

// const uint32_t gDefaultCap = 5;

// template<class T>
// class BlockQueue
// {
// public:
//     BlockQueue(uint32_t cap = gDefaultCap)
//         :cap_(cap)
//     {
//         pthread_mutex_init(&mutex_, nullptr);
//         pthread_cond_init(&conCond_, nullptr);
//         pthread_cond_init(&proCond_, nullptr);
//     }

//     ~BlockQueue()
//     {
//         pthread_mutex_destroy(&mutex_);
//         pthread_cond_destroy(&conCond_);
//         pthread_cond_destroy(&proCond_);
//     }

// public:
//     //生产接口
//     void push(const T& in)
//     {
//         //加锁
//         //判断--是否适合生产--bq_是否为满--程序员视角的条件--1.满-不生产 2.不满-生产
//         //if(满)不生产-休眠; else if(不满)生产-唤醒消费者
//         //解锁

//         lockQueue();

//         while(isFull())//isfull就是我们在临界区设定的条件
//         {
//             //before:当我们等待的时候, 会自动释放mutex_
//             proBlockWait();//生产者阻塞等待,等待被唤醒,被唤醒!=条件被满足  被唤醒&&条件满足
//             //after:当我们醒来的时候,我们是在临界区里醒的
//         }

//         //条件满足,可以生产
//         pushCore(in);//生产完成

//         unlockQueue();

//         wakeupCon();//唤醒消费者
//     }

//     //消费接口
//     T pop()
//     {
//         //加锁
//         //判断--是否适合消费--bq_是否为空--程序员视角的条件--1.空-不消费 2.有-消费
//         //if(空)不消费-休眠 else if(有)消费-唤醒生产者
//         //解锁

//         lockQueue();

//         while(isEmpty())
//         {
//             conBlockWait();//消费者阻塞等待,等待被唤醒
//         }

//         //条件满足,可以消费
//         T tmp = popCore();

//         unlockQueue();

//         wakeupPro();//唤醒生产者

//         return tmp;
//     }

// private:
//     void lockQueue()
//     {
//         pthread_mutex_lock(&mutex_);
//     }

//     void unlockQueue()
//     {
//         pthread_mutex_unlock(&mutex_);
//     }

//     bool isFull()
//     {
//         return bq_.size() == cap_;
//     }

//     bool isEmpty()
//     {
//         return bq_.empty();
//     }

//     void proBlockWait()//生产者一定是在临界区中的
//     {
//         //在阻塞等待(等待条件满足)的时候, 会自动释放mutex_锁
//         pthread_cond_wait(&proCond_, &mutex_);
//     }

//     void conBlockWait()//阻塞等待,等待被唤醒
//     {
//         //1.在阻塞线程的时候,会自动释放mutex_锁
//         pthread_cond_wait(&conCond_, &mutex_);
//         //2.当阻塞结束返回的时候,pthread_cond_wait()会自动帮我们重新获取mutex_,然后才返回
//     }

//     void wakeupPro()//唤醒生产者
//     {
//         pthread_cond_signal(&proCond_);
//     }

//     void wakeupCon()//唤醒消费者
//     {
//         pthread_cond_signal(&conCond_);
//     }

//     void pushCore(const T& in)
//     {
//         bq_.push(in);//生产完成
//     }

//     T popCore()
//     {
//         T tmp = bq_.front();
//         bq_.pop();
//         return tmp;
//     }


// private:
//     uint32_t cap_;//容量
//     queue<T> bq_;//blockqueue
//     pthread_mutex_t mutex_;//保护阻塞队列的互斥锁
//     pthread_cond_t conCond_;//让消费者等待的条件变量
//     pthread_cond_t proCond_;//让生产者等待的条件变量
// };


#pragma once

#include<iostream>
#include<cstdio>
#include<queue>
#include<pthread.h>
using namespace std;

const uint32_t gDefaultCap = 5;

template<class T>
class BlockQueue
{
public:
    BlockQueue(uint32_t cap = gDefaultCap)
        :cap_(cap)
    {
        pthread_mutex_init(&mutex_, nullptr);
        pthread_cond_init(&conCond_, nullptr);
        pthread_cond_init(&proCond_, nullptr);
    }
    ~BlockQueue()
    {
        pthread_mutex_destroy(&mutex_);
        pthread_cond_destroy(&conCond_);
        pthread_cond_destroy(&proCond_);
    }

public:
    //生产接口
    void push(const T& in)
    {
        //加锁
        //判断是否适合生产 -> bq_是否为满 -> 程序员视角的条件 -> 1.满(不生产) 2.不满(生产)
        //if(满)不生产,休眠; else if(不满)生产,唤醒消费者
        //解锁
        lockQueue();

        while(isFull())//isFull()就是在临界区设定的条件
        {
            //before:当我们等待的时候,会自动释放mutex_
            proBlockWait();//生产者阻塞等待,等待被唤醒,被唤醒!=条件被满足   被唤醒&&条件被满足
            //after:当我醒来的时候,我是在临界区里醒的
        }

        //条件满足,可以生产
        pushCore(in);//生产完成

        unlockQueue();

        wakeupCon();//唤醒消费者
    }

    //消费接口
    T pop()
    {
        //加锁
        //判断是否适合消费 -> bq_是否为空 -> 程序员视角的条件 -> 1.空(不消费)2.非空(消费)
        //if(空)不消费,休眠 else if(非空)消费,唤醒生产者
        //解锁
        lockQueue();

        while(isEmpty())
        {
            conBlockWait();//消费者阻塞等待,等待被唤醒
        }

        //条件满足,可以消费
        T tmp = popCore();

        unlockQueue();

        wakeupPro();//唤醒生产者

        return tmp;
    }

private:
    void lockQueue()
    {
        pthread_mutex_lock(&mutex_);
    }
    void unlockQueue()
    {
        pthread_mutex_unlock(&mutex_);
    }

    bool isEmpty()
    {
        return bq_.empty();
    }
    bool isFull()
    {
        return bq_.size() == cap_;
    }

    void proBlockWait()//生产者一定是在临界区中的
    {
        //1.在阻塞等待的时候,会自动释放mutex_
        pthread_cond_wait(&proCond_, &mutex_);
        //2.当阻塞结束返回的时候,pthread_cond_wait()会自动帮你重新获得mutex_,然后才返回
    }
    void conBlockWait()//阻塞等待,等待被唤醒
    {
        //1.在阻塞等待的时候,会自动释放mutex_
        pthread_cond_wait(&conCond_, &mutex_);
        //2.当阻塞结束返回的时候,pthread_cond_wait()会自动帮你重新获得mutex_,然后才返回
    }

    void wakeupPro()//唤醒生产者
    {
        pthread_cond_signal(&proCond_);
    }
    void wakeupCon()//唤醒消费者
    {
        pthread_cond_signal(&conCond_);
    }

    void pushCore(const T& in)
    {
        bq_.push(in);//生产完成
    }
    T popCore()
    {
        T tmp = bq_.front();
        bq_.pop();
        return tmp;
    }


private:
    uint32_t cap_; // 容量
    queue<T> bq_; // bolckqueue
    pthread_mutex_t mutex_; // 保护阻塞队列的互斥锁
    pthread_cond_t conCond_; // 让消费者等待的条件变量
    pthread_cond_t proCond_; // 让生产者等待的条件变量
};